package com.celements.web.service; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.validation.constraints.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xwiki.component.annotation.Component; import org.xwiki.component.annotation.Requirement; import org.xwiki.context.Execution; import org.xwiki.model.reference.DocumentReference; import com.celements.model.access.IModelAccessFacade; import com.celements.model.access.exception.DocumentLoadException; import com.celements.model.access.exception.DocumentNotExistsException; import com.celements.model.access.exception.DocumentSaveException; import com.celements.rendering.RenderCommand; import com.celements.web.UserCreateException; import com.celements.web.plugin.cmd.PasswordRecoveryAndEmailValidationCommand; import com.celements.web.plugin.cmd.PossibleLoginsCommand; import com.celements.web.plugin.cmd.UserNameForUserDataCommand; import com.celements.web.token.NewCelementsTokenForUserCommand; import com.xpn.xwiki.XWikiContext; import com.xpn.xwiki.XWikiException; import com.xpn.xwiki.doc.XWikiDocument; import com.xpn.xwiki.objects.BaseObject; import com.xpn.xwiki.user.api.XWikiUser; import com.xpn.xwiki.util.Util; import com.xpn.xwiki.web.XWikiResponse; @Component public class CelementsWebService implements ICelementsWebServiceRole { private static Logger _LOGGER = LoggerFactory.getLogger(CelementsWebService.class); private List<String> supportedAdminLangList; @Requirement private IWebUtilsService webUtilsService; @Requirement IModelAccessFacade modelAccess; @Requirement private Execution execution; private XWikiContext getContext() { return (XWikiContext) execution.getContext().getProperty("xwikicontext"); } public String getEmailAdressForUser(String username) { return getEmailAdressForUser(webUtilsService.resolveDocumentReference(username)); } @Override public String getEmailAdressForUser(DocumentReference userDocRef) { if (getContext().getWiki().exists(userDocRef, getContext())) { try { XWikiDocument doc = getContext().getWiki().getDocument(userDocRef, getContext()); BaseObject obj = doc.getXObject(webUtilsService.resolveDocumentReference( "XWiki.XWikiUsers")); if (obj != null) { return obj.getStringValue("email"); } } catch (XWikiException exp) { _LOGGER.error("Exception while getting a XWikiDocument. docRef:['" + userDocRef + "]'", exp); } } return null; } @Override public int createUser(boolean validate) throws XWikiException { String possibleLogins = new PossibleLoginsCommand().getPossibleLogins(); return createUser(getUniqueNameValueRequestMap(), possibleLogins, validate); } @Override public synchronized int createUser(Map<String, String> userData, String possibleLogins, boolean validate) throws XWikiException { try { if (createNewUser(userData, possibleLogins, validate) != null) { return 1; } } catch (UserCreateException uce) { if (uce.getCause() instanceof XWikiException) { throw (XWikiException) uce.getCause(); } else { throw new XWikiException(XWikiException.MODULE_XWIKI_STORE, XWikiException.ERROR_XWIKI_UNKNOWN, "failed to create user", uce); } } return -1; } @Override public synchronized @NotNull XWikiUser createNewUser(@NotNull Map<String, String> userData, @NotNull String possibleLogins, boolean validate) throws UserCreateException { String accountName = ""; String accountFullName = null; if (userData.containsKey("xwikiname")) { accountName = userData.get("xwikiname"); userData.remove("xwikiname"); } else { while (accountName.equals("") || getContext().getWiki().exists( webUtilsService.resolveDocumentReference(accountFullName), getContext())) { accountName = getContext().getWiki().generateRandomString(12); accountFullName = "XWiki." + accountName; } } String validkey = ""; int success = -1; try { if (areIdentifiersUnique(userData, possibleLogins, getContext())) { if (!userData.containsKey("password")) { String password = getContext().getWiki().generateRandomString(8); userData.put("password", password); } if (!userData.containsKey("validkey")) { validkey = new NewCelementsTokenForUserCommand().getUniqueValidationKey(getContext()); userData.put("validkey", validkey); } else { validkey = userData.get("validkey"); } if (!userData.containsKey("active")) { userData.put("active", "0"); } String content = "#includeForm(\"XWiki.XWikiUserSheet\")"; success = getContext().getWiki().createUser(accountName, userData, webUtilsService.resolveDocumentReference("XWiki.XWikiUsers"), content, null, "edit", getContext()); } } catch (XWikiException excp) { _LOGGER.error("Exception while creating a new user", excp); throw new UserCreateException(excp); } XWikiUser newUser = null; if (success == 1) { setRightsOnUserDoc(accountFullName); newUser = new XWikiUser(accountFullName); if (validate) { _LOGGER.info("send account validation mail with data: accountname='" + accountName + "', email='" + userData.get("email") + "', validkey='" + validkey + "'"); try { new PasswordRecoveryAndEmailValidationCommand().sendValidationMessage(userData.get( "email"), validkey, webUtilsService.resolveDocumentReference( "Tools.AccountActivationMail"), webUtilsService.getDefaultAdminLanguage()); } catch (XWikiException e) { _LOGGER.error("Exception while sending validation mail to '" + userData.get("email") + "'", e); throw new UserCreateException(e); } } } if (newUser == null) { throw new UserCreateException("Failed to create a new user"); } return newUser; } void setRightsOnUserDoc(@NotNull String accountFullName) throws UserCreateException { try { XWikiDocument doc = modelAccess.getDocument(webUtilsService.resolveDocumentReference( accountFullName)); List<BaseObject> rightsObjs = doc.getXObjects(webUtilsService.resolveDocumentReference( "XWiki.XWikiRights")); for (BaseObject rightObj : rightsObjs) { if (rightObj.getStringValue("groups").equals("")) { rightObj.setStringValue("users", webUtilsService.getRefLocalSerializer().serialize( doc.getDocumentReference())); rightObj.set("allow", "1", getContext()); rightObj.set("levels", "view,edit,delete", getContext()); rightObj.set("groups", "", getContext()); } else { rightObj.set("users", "", getContext()); rightObj.set("allow", "1", getContext()); rightObj.set("levels", "view,edit,delete", getContext()); rightObj.set("groups", "XWiki.XWikiAdminGroup", getContext()); } } modelAccess.saveDocument(doc, "added rights objects to created user"); } catch (DocumentLoadException | DocumentNotExistsException | DocumentSaveException excp) { _LOGGER.error("Exception while trying to add rights to newly created user", excp); throw new UserCreateException(excp); } } @SuppressWarnings("unchecked") @Override public Map<String, String> getUniqueNameValueRequestMap() { Map<String, String[]> params = getContext().getRequest().getParameterMap(); Map<String, String> resultMap = new HashMap<String, String>(); for (String key : params.keySet()) { if ((params.get(key) != null) && (params.get(key).length > 0)) { resultMap.put(key, params.get(key)[0]); } else { resultMap.put(key, ""); } } return resultMap; } private boolean areIdentifiersUnique(Map<String, String> userData, String possibleLogins, XWikiContext context) throws XWikiException { boolean isUnique = true; for (String key : userData.keySet()) { if (!"".equals(key.trim()) && (("," + possibleLogins + ",").indexOf("," + key + ",") >= 0)) { String user = new UserNameForUserDataCommand().getUsernameForUserData(userData.get(key), possibleLogins, context); if ((user == null) || (user.length() > 0)) { // user == "" means there is no such // user isUnique = false; } } } return isUnique; } @Override public List<String> getSupportedAdminLanguages() { if (supportedAdminLangList == null) { supportedAdminLangList = Arrays.asList(new String[] { "de", "fr", "en", "it" }); } return supportedAdminLangList; } @Override public boolean writeUTF8Response(String filename, String renderDocFullName) { boolean success = false; if (getContext().getWiki().exists(webUtilsService.resolveDocumentReference(renderDocFullName), getContext())) { XWikiDocument renderDoc; try { renderDoc = getContext().getWiki().getDocument(webUtilsService.resolveDocumentReference( renderDocFullName), getContext()); adjustResponseHeader(filename, getContext().getResponse()); setResponseContent(renderDoc, getContext().getResponse()); } catch (XWikiException e) { _LOGGER.error("", e); } getContext().setFinished(true); } return success; } private void adjustResponseHeader(String filename, XWikiResponse response) { response.setContentType("text/plain"); String ofilename = Util.encodeURI(filename, getContext()).replaceAll("\\+", " "); response.addHeader("Content-disposition", "attachment; filename=\"" + ofilename + "\"; charset='UTF-8'"); } private void setResponseContent(XWikiDocument renderDoc, XWikiResponse response) throws XWikiException { String renderedContent = new RenderCommand().renderDocument(renderDoc); byte[] data = {}; try { data = renderedContent.getBytes("UTF-8"); } catch (UnsupportedEncodingException e1) { e1.printStackTrace(); } response.setContentLength(data.length + 3); try { response.getOutputStream().write(new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF }); response.getOutputStream().write(data); } catch (IOException e) { throw new XWikiException(XWikiException.MODULE_XWIKI_APP, XWikiException.ERROR_XWIKI_APP_SEND_RESPONSE_EXCEPTION, "Exception while sending response", e); } } @Override public void setSupportedAdminLanguages(List<String> supportedAdminLangList) { this.supportedAdminLangList = supportedAdminLangList; } }